﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Reflection;
using Pixysoft.Tools;

namespace Pixysoft.Reflection
{
    public class ReflectHelper
    {
        private const string default_reflection_index = "Item";

        private static volatile ReflectHelper instance;

        private static object syncRoot = new Object();

        public static ReflectHelper Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (syncRoot)
                    {
                        instance = new ReflectHelper();
                    }
                }

                return instance;

            }
        }


        public bool IsPrivateClass(Type type)
        {
            if (!type.IsClass)
                return false;

            if (type.IsNested)
            {
                if (type.IsNestedPublic)
                    return false;
                else
                    return true;
            }

            if (type.IsPublic)
                return false;

            return true;
        }

        public bool IsPrivateEnum(Type type)
        {
            if (!type.IsEnum)
                return false;

            if (type.IsNested)
            {
                if (type.IsNestedPublic)
                    return false;
                else
                    return true;
            }

            if (type.IsPublic)
                return false;

            return true;
        }

        public bool IsBaseClass(Type type)
        {
            if (type == null)
                throw new Exception("missing input.");

            if (type.BaseType.Name.ToUpper() != "OBJECT" && type.BaseType.Name.ToUpper() != "VALUETYPE")
                return false;

            return true;
        }

        public bool HasAttribute(MemberInfo member, Type attributeType)
        {
            foreach (object customerAttribute in member.GetCustomAttributes(true))
            {
                Type customerAttributeType = customerAttribute.GetType();

                if (string.IsNullOrEmpty(customerAttributeType.FullName) && string.IsNullOrEmpty(attributeType.FullName))
                {
                    if (string.Equals(customerAttributeType.Name, attributeType.Name))
                        return true;
                }
                else if (string.Equals(customerAttributeType.FullName, attributeType.FullName))
                {
                    return true;
                }
            }
            return false;
        }

        public bool IsIndexProperty(PropertyInfo info)
        {
            if (info.CanRead && info.GetGetMethod(true).GetParameters().Length > 0)
                return true;

            //10-04-11 如果是internal / private的方法 会返回null

            if (info.CanWrite && info.GetSetMethod(true).GetParameters().Length > 1)
                return true;

            return false;
        }

        public bool IsAttributeProperty(PropertyInfo info)
        {
            Type declaretype = info.DeclaringType;

            return string.Equals(RegularTypeName(declaretype), RegularTypeName(typeof(Attribute)));
        }

        public bool IsIndexMethod(MethodInfo method)
        {
            foreach (PropertyInfo info in method.DeclaringType.GetProperties())
            {
                if (!IsIndexProperty(info))
                    continue;

                if (info.CanRead && info.GetGetMethod(true) == method)
                    return true;

                if (info.CanWrite && info.GetSetMethod(true) == method)
                    return true;
            }

            return false;
        }

        public bool IsPropertyMethod(MethodBase method)
        {
            foreach (PropertyInfo info in method.DeclaringType.GetProperties())
            {
                if (info.CanRead && info.GetGetMethod(true) == method)
                    return true;

                if (info.CanWrite && info.GetSetMethod(true) == method)
                    return true;
            }

            return false;
        }


        /// <summary>
        /// 修正范型名称，删除~1后缀 同时考虑到内联类的问题
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public string RegularTypeName(Type type)
        {
            if (type == null)
                return null;

            string typename = null;

            if (string.IsNullOrEmpty(type.FullName))
                typename = type.Name;
            else
                typename = type.FullName;


            return RegularTypeName(typename);
        }

        /// <summary>
        /// 修正范型名称，删除~1后缀 同时考虑到内联类的问题
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public string RegularTypeName(string typename)
        {
            if (string.IsNullOrEmpty(typename))
                return typename;

            StringBuilder builder = new StringBuilder();

            foreach (string subname in typename.Split(new char[] { '+' }, StringSplitOptions.RemoveEmptyEntries))
            {
                string newsubname = subname.Split(new char[] { '`' }, StringSplitOptions.RemoveEmptyEntries)[0];

                builder.Append(newsubname);

                builder.Append("+");
            }

            builder.Remove(builder.Length - 1, 1);

            typename = builder.ToString();

            return typename;
        }

        /// <summary>
        /// 取得自定义的标签
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="type"></param>
        /// <returns></returns>
        public T GetCustomerAttribute<T>(MemberInfo type)
        {
            Type attributeType = typeof(T);

            string typeFullName = attributeType.FullName;

            if (string.IsNullOrEmpty(typeFullName))
                typeFullName = attributeType.Name;

            foreach (object targetAttribute in type.GetCustomAttributes(true))
            {
                Type targetAttributeType = targetAttribute.GetType();

                string targetTypeFullName = targetAttributeType.FullName;

                if (string.IsNullOrEmpty(targetTypeFullName))
                    targetTypeFullName = targetAttributeType.Name;

                if (string.Equals(typeFullName, targetTypeFullName))
                    return (T)targetAttribute;
            }

            return default(T);
        }

        /// <summary>
        /// 取得自定义的标签
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="type"></param>
        /// <returns></returns>
        public T[] GetCustomerAttributes<T>(MemberInfo type)
        {
            List<T> list = new List<T>();

            Type attributeType = typeof(T);

            string typeFullName = attributeType.FullName;

            if (string.IsNullOrEmpty(typeFullName))
                typeFullName = attributeType.Name;

            foreach (object targetAttribute in type.GetCustomAttributes(true))
            {
                Type targetAttributeType = targetAttribute.GetType();

                string targetTypeFullName = targetAttributeType.FullName;

                if (string.IsNullOrEmpty(targetTypeFullName))
                    targetTypeFullName = targetAttributeType.Name;

                if (string.Equals(typeFullName, targetTypeFullName))
                    list.Add((T)targetAttribute);
            }

            return list.ToArray();
        }

        /// <summary>
        /// 获取继承的interface
        /// </summary>
        /// <param name="type"></param>
        /// <param name="interfacetype"></param>
        /// <returns></returns>
        public Type GetInheritInterface(Type type, Type interfacetype)
        {
            foreach (Type tinterfacetype in type.GetInterfaces())
            {
                if (string.Equals(RegularTypeName(tinterfacetype), RegularTypeName(interfacetype)))
                    return tinterfacetype;
            }

            return null;
        }

        /// <summary>
        /// 获取包含继承关系的property
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public PropertyInfo[] GetInterfaceProperties(Type type)
        {
            if (!type.IsInterface)
                throw new VerificationFailedException("only support interface type.");

            List<PropertyInfo> list = new List<PropertyInfo>();

            foreach (PropertyInfo info in type.GetProperties())
            {
                list.Add(info);
            }

            foreach (Type itype in type.GetInterfaces())
            {
                list.AddRange(GetInterfaceProperties(itype));
            }

            return list.ToArray();
        }

        /// <summary>
        /// 包括继承关系 搜索接口的属性
        /// </summary>
        /// <param name="type"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public PropertyInfo GetInterfaceProperty(Type type, string name)
        {
            if (!type.IsInterface)
                throw new VerificationFailedException("only support interface type.");

            PropertyInfo info = type.GetProperty(name);

            if (info != null)
                return info;

            foreach (Type itype in type.GetInterfaces())
            {
                info = GetInterfaceProperty(itype, name);

                if (info != null)
                    return info;
            }

            return null;
        }

        /// <summary>
        /// 获取包含继承关系的method
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public MethodInfo[] GetInterfaceMethods(Type type)
        {
            if (!type.IsInterface)
                throw new VerificationFailedException("only support interface type.");

            List<MethodInfo> list = new List<MethodInfo>();

            foreach (MethodInfo info in type.GetMethods())
            {
                list.Add(info);
            }

            foreach (Type itype in type.GetInterfaces())
            {
                list.AddRange(GetInterfaceMethods(itype));
            }

            return list.ToArray();
        }

        public void SetPropertyValue<T>(T obj, string field, object value)
        {
            SetPropertyValue(obj, field, value);
        }

        public void SetPropertyValue(object obj, string field, object value)
        {
            if (value == null || value.GetType().Equals(typeof(DBNull)))
                return;

            Type type = obj.GetType();

            PropertyInfo info = GetPropertyInfo(obj, field);

            if (info == null)
                if (type.BaseType.Name.ToUpper() != "OBJECT" && type.BaseType.Name.ToUpper() != "VALUETYPE")
                {
                    SetPropertyValue(obj, field, value);
                }
                else
                {
                    return;
                }


            try
            {
                //要根据不同的类型去设置

                if (value == null)
                    info.SetValue(obj, value, null);
                else
                {
                    object pvalue = null;

                    ParserHelper.TryParse(info.PropertyType, value, out pvalue, null);

                    info.SetValue(obj, pvalue, null);
                }

            }
            catch (Exception ex)
            {
                StringBuilder builder = new StringBuilder();

                builder.AppendLine(string.Format("set property failed, objename = {0}, propertyname = {1}, propertyvalue = {2}",
                    type.Name, field, value));

                builder.AppendLine(ex.ToString());

                throw new Exception(builder.ToString());
            }
        }

        public T GetPropertyValue<T>(object obj, string field)
        {
            Type type = obj.GetType();

            PropertyInfo info = GetPropertyInfo(obj, field);

            if (info == null)
                if (type.BaseType.Name.ToUpper() != "OBJECT" && type.BaseType.Name.ToUpper() != "VALUETYPE")
                {
                    return GetPropertyValue<T>(obj, field);
                }
                else
                {
                    return default(T);
                }

            try
            {
                object value = info.GetValue(obj, null);

                return (T)value;
            }
            catch
            {
                return default(T);
            }
        }

        public object GetPropertyValue(object obj, string field)
        {
            Type type = obj.GetType();

            PropertyInfo info = GetPropertyInfo(obj, field);

            if (info == null)
                if (type.BaseType.Name.ToUpper() != "OBJECT" && type.BaseType.Name.ToUpper() != "VALUETYPE")
                {
                    return GetPropertyValue(obj, field);
                }
                else
                {
                    return null;
                }

            try
            {
                object value = info.GetValue(obj, null);

                return value;
            }
            catch
            {
                return null;
            }
        }

        private PropertyInfo GetPropertyInfo(object obj, string field)
        {
            if (string.IsNullOrEmpty(field))
                return null;

            foreach (PropertyInfo info in obj.GetType().GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public))
            {
                if (info.Name.Trim().ToUpper() == field.Trim().ToUpper())
                    return info;
            }

            return null;
        }

        private PropertyInfo GetPropertyInfo<T>(T obj, string field)
        {
            if (string.IsNullOrEmpty(field))
                return null;

            foreach (PropertyInfo info in typeof(T).GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public))
            {
                if (info.Name.Trim().ToUpper() == field.Trim().ToUpper())
                    return info;
            }

            return null;
        }
    }
}
